﻿/*********************************************************
 * copyright learnren.com 版权所有
 * 开发人员：minyuan
 * 创建时间：2015/11/3 5:20:51
 * 描述说明：
 *
 * 更改历史：
 *
 ********************************************************/

using Newtonsoft.Json;
using System;
using System.Net;
using System.Web;

namespace NQQOpenApi
{
    /// <summary>
    /// PC网站接入API管理类
    /// </summary>
    public class PCApiManager
    {
        private const string emptyResponseMsg = "发生意外错误。QQ服务器返回结果为空。";

        #region ctor

        public PCApiManager()
        {

        }

        public PCApiManager(string appId, string appKey)
        {
            this.AppId = appId;
            this.AppKey = appKey;
        }

        #endregion

        #region 属性

        /// <summary>
        /// 从http://connect.qq.com申请到的appid
        /// </summary>
        public string AppId { get; set; }

        /// <summary>
        /// 从http://connect.qq.com申请到的appkey
        /// </summary>
        public string AppKey { get; set; }

        #endregion 属性

        #region 接口方法

        /// <summary>
        /// 获取QQ登录窗口地址
        /// </summary>
        /// <param name="redirectUrl">成功授权后的回调地址，必须是注册appid时填写的主域名下的地址，
        /// 建议设置为网站首页或网站的用户中心。方法内部自动对此参数进行url编码。</param>
        /// <param name="state">client端的状态值。用于第三方应用防止CSRF攻击，
        /// 成功授权后回调时会原样带回。请务必严格按照流程检查用户与state参数状态的绑定。</param>
        /// <param name="scope">请求用户授权时向用户显示的可进行授权的列表。
        /// 可填写的值是API文档中列出的接口，以及一些动作型的授权（目前仅有：do_like），如果要填写多个接口名称，请用逗号隔开。
        /// 例如：scope=get_user_info,list_album,upload_pic,do_like
        /// 不传则默认请求对接口get_user_info进行授权。</param>
        /// <param name="display">仅PC网站接入时使用。
        /// 用于展示的样式。不传则默认展示为PC下的样式。
        /// 如果传入“mobile”，则展示为mobile端下的样式。</param>
        /// <returns></returns>
        public string GetLoginUrl(string redirectUrl, string state, string scope = null, string display = null)
        {
            if (string.IsNullOrEmpty(redirectUrl))
            {
                throw new System.ArgumentException("redirectUrl不能为空或空字符串");
            }

            if (string.IsNullOrEmpty(state))
            {
                throw new System.ArgumentException("state不能为空或空字符串");
            }

            string result = string.Format("{0}?response_type=code&client_id={1}&redirect_uri={2}&state={3}",
                ApiUrls.PC_GETAUTHORIZECODE,
                AppId,
                HttpUtility.UrlEncode(redirectUrl),
                state);
            if (!string.IsNullOrEmpty(scope))
            {
                result += string.Format("&scope={0}", scope);
            }
            if (!string.IsNullOrEmpty(display))
            {
                result += string.Format("&display={0}", display);
            }
            return result;
        }

        /// <summary>
        /// 获取Access Token
        /// </summary>
        /// <param name="code">服务端返回到回调地址的authorization code</param>
        /// <param name="redirectUrl">与GetLoginUrl中传入的redirect_uri保持一致。</param>
        /// <returns></returns>
        public PCAccessToken GetAccessToken(string code, string redirectUrl)
        {
            string url = string.Format("{0}?grant_type=authorization_code&client_id={1}&client_secret={2}&code={3}&redirect_uri={4}",
                        ApiUrls.PC_GETTOKEN,
                        AppId,
                        AppKey,
                        code,
                        HttpUtility.UrlEncode(redirectUrl));
            string response = null;
            try
            {
                using (WebClient wc = new WebClient())
                {
                    wc.Encoding = System.Text.Encoding.UTF8;
                    response = wc.DownloadString(url);
                }
            }
            catch
            {
                throw;
            }

            if (string.IsNullOrEmpty(response))
            {
                return GetErrorAccessToken("-1", emptyResponseMsg);
            }

            if (response.IndexOf("{") == -1)
            {
                // 如是正确返回转换为json
                response = TranslateUrlToJson(response);
            }
            else
            {
                // 截取返回结果中json，针对返回callback({})格式错误信息处理
                response = GetResponseJson(response);
            }

            PCAccessToken result = null;

            try
            {
                result = JsonConvert.DeserializeObject<PCAccessToken>(response);
            }
            catch { }

            if (result == null)
                result = new PCAccessToken();

            if (string.IsNullOrEmpty(result.AccessToken))
            {
                try
                {
                    result.Error = JsonConvert.DeserializeObject<ErrorMessage>(response);
                }
                catch (Exception ex)
                {
                    result = GetErrorAccessToken("-1", "发生意外错误。" + ex);
                }
                return result;
            }

            result.Error = new ErrorMessage { ErrorCode = "0", ErrorDescription = "OK" };
            return result;
        }

        /// <summary>
        /// 刷新AccessToken,以自动延期
        /// </summary>
        /// <param name="refreshToken">获取或刷新AccessToken时，服务器同时返回的refreshToken</param>
        /// <returns></returns>
        public PCAccessToken RefreshAccessToken(string refreshToken)
        {
            string url = string.Format("{0}?grant_type=refresh_token&client_id={1}&client_secret={2}&refresh_token={4}",
                                        ApiUrls.PC_GETTOKEN,
                                        AppId,
                                        AppKey,
                                        refreshToken);
            string response = null;
            try
            {
                using (WebClient wc = new WebClient())
                {
                    wc.Encoding = System.Text.Encoding.UTF8;
                    response = wc.DownloadString(url);
                }
            }
            catch
            {
                throw;
            }

            if (string.IsNullOrEmpty(response))
            {
                return GetErrorAccessToken("-1", emptyResponseMsg);
            }

            if (response.IndexOf("{") == -1)
            {
                // 如是正确返回转换为json
                response = TranslateUrlToJson(response);
            }
            else
            {
                // 截取返回结果中json，针对返回callback({})格式错误信息处理
                response = GetResponseJson(response);
            }

            PCAccessToken result = null;

            try
            {
                result = JsonConvert.DeserializeObject<PCAccessToken>(response);
            }
            catch { }

            if (result == null)
                result = new PCAccessToken();

            if (string.IsNullOrEmpty(result.AccessToken))
            {
                try
                {
                    result.Error = JsonConvert.DeserializeObject<ErrorMessage>(response);
                }
                catch (Exception ex)
                {
                    result = GetErrorAccessToken("-1", "发生意外错误。" + ex);
                }
                return result;
            }

            result.Error = new ErrorMessage { ErrorCode = "0", ErrorDescription = "OK" };
            return result;
        }

        /// <summary>
        /// 根据用户access_token获取用户的OpenID
        /// </summary>
        /// <param name="access_token">AccessToken字符串</param>
        /// <returns></returns>
        public PCOpenID GetOpenID(string access_token)
        {
            string url = string.Format("{0}?access_token={1}",
                                        ApiUrls.PC_ME,
                                        access_token);
            string response = null;

            using (var client = new WebClient())
            {
                client.Encoding = System.Text.Encoding.UTF8;
                response = client.DownloadString(url);
            }

            if (string.IsNullOrEmpty(response))
            {
                return new PCOpenID
                {
                    Error = new ErrorMessage
                    {
                        ErrorCode = "-1",
                        ErrorDescription = emptyResponseMsg
                    }
                };
            }

            // 截取返回结果中json，针对返回callback({})格式错误信息处理
            response = GetResponseJson(response);

            PCOpenID result = null;
            try
            {
                result = JsonConvert.DeserializeObject<PCOpenID>(response);
            }
            catch { }

            if (result == null)
                result = new PCOpenID();

            if (string.IsNullOrEmpty(result.AppID))
            {
                try
                {
                    result.Error = JsonConvert.DeserializeObject<ErrorMessage>(response);
                }
                catch (Exception ex)
                {
                    result.Error = new ErrorMessage
                    {
                        ErrorCode = "-1",
                        ErrorDescription = "发生内部错误。" + ex
                    };
                }
                return result;
            }

            result.Error = new ErrorMessage { ErrorCode = "0", ErrorDescription = "OK" };
            return result;
        }

        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <param name="access_token">access_token</param>
        /// <param name="openid">openid</param>
        /// <returns></returns>
        public PCUserInfo GetUserInfo(string access_token, string openid)
        {
            string url = string.Format("{0}?oauth_consumer_key={1}&access_token={2}&openid={3}",
                                       ApiUrls.PC_GETUSERINFO,
                                       AppId,
                                       access_token,
                                       openid
                                       );
            string response = null;

            try
            {
                using (var client = new WebClient())
                {
                    client.Encoding = System.Text.Encoding.UTF8;
                    response = client.DownloadString(url);
                }
            }
            catch
            {
                throw;
            }

            if (string.IsNullOrEmpty(response))
            {
                return new PCUserInfo { Ret = "-1000", Message = emptyResponseMsg };
            }

            return JsonConvert.DeserializeObject<PCUserInfo>(response);
        }

        #endregion 接口方法

        #region 私有方法

        /// <summary>
        /// 将URL参数格式的字符串转换成json格式
        /// </summary>
        /// <param name="response">服务器返回的字符串</param>
        /// <returns></returns>
        private string TranslateUrlToJson(string response)
        {
            return "{'" + response.Replace("&", "','").Replace("=", "':'") + "'}";
        }

        /// <summary>
        /// 从返回的信息中截取Json字符串
        /// </summary>
        /// <param name="response">服务器返回信息</param>
        /// <returns></returns>
        private string GetResponseJson(string response)
        {
            int start = response.IndexOf("{");
            if (start > -1)
            {
                response = response.Substring(start);
            }

            int end = response.LastIndexOf("}");
            if (end > -1)
            {
                response = response.Substring(0, end + 1);
            }
            return response;
        }

        /// <summary>
        /// 生成一个标记为错误的AccessToken
        /// </summary>
        /// <param name="code">错误编码</param>
        /// <param name="msg">错误提示</param>
        /// <returns></returns>
        private PCAccessToken GetErrorAccessToken(string code, string msg)
        {
            return new PCAccessToken
            {
                Error = new ErrorMessage
                {
                    ErrorCode = code,
                    ErrorDescription = msg
                }
            };
        }

        #endregion 私有方法
    }
}
